package log

import (
	"fmt"
	"runtime"
	"strings"
	"time"
)

// LogLevel log level
type LogLevel int

const (
	SilentL LogLevel = iota + 1
	ErrorL
	WarnL
	InfoL
)

// Interface logger interface
type LogFacer interface {
	//LogMode(LogLevel) LogFacer
	Info(format string, v ...interface{})
	Warn(format string, v ...interface{})
	Error(format string, v ...interface{})
}

var l = &Logger{Level: InfoL}

func SetLogger(logger *LogFacer) {
	l.log = *logger
}

func SetLoggerLevel(level LogLevel) {
	l.Level = level
}

type Logger struct {
	log   LogFacer
	Level LogLevel
}

func (l *Logger) Info(format string, v ...interface{}) {
	if l.Level < InfoL {
		return
	}
	// 实现 Info 方法
	if ll, ok := l.log.(LogFacer); ok {
		ll.Info(format, v)
	} else {
		///fmt.Printf(format, v)
		fmt.Println(format)
	}
}

func (l *Logger) Warn(format string, v ...interface{}) {
	if l.Level < WarnL {
		return
	}
	if ll, ok := l.log.(LogFacer); ok {
		ll.Warn(format, v)
	} else {
		//fmt.Printf(format, v)
		fmt.Println(format)
	}
}

func (l *Logger) Error(format string, v ...interface{}) {
	if l.Level < ErrorL {
		return
	}

	if ll, ok := l.log.(LogFacer); ok {
		ll.Error(format, v)
	} else {
		//fmt.Printf(format, v)
		fmt.Println(format)
	}
}

func Info(format string, v ...interface{}) {
	if l.Level < InfoL {
		return
	}
	l.Info(GetInfoCallerOutput(infoColor, 2, format, v...))
}

func Error(v ...interface{}) {
	if l.Level < ErrorL {
		return
	}
	l.Error(GetInfoCallerOutput(errColor, 2, "%s", v...))
}

var (
	errColor  = "\033[31m[error]\033[0m "
	warnColor = "\033[33m[warn]\033[0m "
	infoColor = "\033[34m[info ]\033[0m "
)

// log methods
/*var (
	Error  = errorLog.Println
	Errorf = errorLog.Printf
	Info   = infoLog.Println
	Infof  = infoLog.Printf
)*/

// log levels
/*const (
	InfoLevel = iota
	ErrorLevel
	Disabled
)
*/
// SetLevel controls log level
/*func SetLevel(level int) {
	mu.Lock()
	defer mu.Unlock()

	for _, logger := range loggers {
		logger.SetOutput(os.Stdout)
	}

	if ErrorLevel < level {
		errorLog.SetOutput(ioutil.Discard)
	}
	if InfoLevel < level {
		infoLog.SetOutput(ioutil.Discard)
	}
}*/

func Errorf(format string, v ...interface{}) {
	l.Error(GetInfoCallerOutput(errColor, 3, format, v...))
}

func Infof(format string, v ...interface{}) {
	l.Info(GetInfoCallerOutput(infoColor, 3, format, v...))
}

func InfoCaller(format string, v ...interface{}) {
	l.Info(GetInfoCallerOutput(infoColor, 5, format, v...))
}

func ErrorCaller(format string, v ...interface{}) {
	l.Error(GetInfoCallerOutput(errColor, 8, format, v...))
}

func InfofCaller(format string, v ...interface{}) {
	l.Info(GetInfoCallerOutput(infoColor, 8, format, v...))
}

func InfofCallerPage(format string, v ...interface{}) {
	l.Info(GetInfoCallerOutput(infoColor, 9, format, v...))
}

func GetInfoCallerOutput(color string, skip int, format string, v ...interface{}) string {
	return fmt.Sprintf(" %s %s %s %s ", color, time.Now().Format("2006/01/02 15:04:05"), fileWithLineNum(skip), fmt.Sprintf(format, v...))
}

func fileWithLineNum(skip int) string {
	_, file, line, ok := runtime.Caller(skip)
	if !ok {
		file = "???"
		line = 0
	} else {
		idx := strings.LastIndex(file, "/")
		if idx >= 0 {
			file = file[idx+1:]
		}
	}
	return fmt.Sprintf("%s:%d", file, line)
}
